use crate::commands::command::{parse_expire_flags, CmdAttr, Command};
use crate::commands::common::{ErrMsg, SYNTAX_ERR};
use crate::commands::parser::CommandParser;
use crate::commands::redis::ContentType::{BULK, SIMPLE};
use crate::commands::redis::{RedisRequest, RedisResponse};
use bytes::Bytes;

#[derive(Default)]
enum StringSetType {
    #[default]
    None,
    NX,
    XX,
}

#[derive(Default)]
pub struct CommandGet {
    key: Bytes,
}

impl Command for CommandGet {
    fn parse(&mut self, req: &RedisRequest) -> Result<(), ErrMsg> {
        self.key = Bytes::copy_from_slice(req.get_key());
        Ok(())
    }

    fn execute(&self) -> Result<RedisResponse, ErrMsg> {
        let mut response = RedisResponse::new();
        response.set_field_type(BULK);
        response.set_message(self.key.to_vec());
        Ok(response)
    }

    fn attr(&self) -> CmdAttr {
        GET_CMD_ATTR
    }
}

#[derive(Default)]
pub struct CommandSet {
    key: Bytes,
    value: Bytes,
    expire: u64,
    get: bool,
    keep_ttl: bool,
    set_flag: StringSetType,
}

impl Command for CommandSet {
    fn parse(&mut self, req: &RedisRequest) -> Result<(), ErrMsg> {
        self.key = Bytes::copy_from_slice(req.get_key());
        self.value = Bytes::copy_from_slice(req.get_args()[0].as_slice());
        
        let mut parser = CommandParser::new(req.get_args().iter());
        parser.skip(1);
        
        let mut ttl_flag = String::new();
        let mut set_flag = String::new();
        while parser.good() {
            if let Ok(Some(v)) = parse_expire_flags(&mut parser, &mut ttl_flag) {
                self.expire = v;
            } else if parser.eat_eq_icase_flag("KEEPTTL", &mut ttl_flag) {
                self.keep_ttl = true;
            } else if parser.eat_eq_icase_flag("NX", &mut set_flag) {
                self.set_flag = StringSetType::NX;
            } else if parser.eat_eq_icase_flag("XX", &mut set_flag) {
                self.set_flag = StringSetType::XX;
            } else if parser.eat_eq_icase("GET") {
                self.get = true;
            } else {
                return Err(SYNTAX_ERR);
            }
        }
        Ok(())
    }

    fn execute(&self) -> Result<RedisResponse, ErrMsg> {
        let mut response = RedisResponse::new();
        response.set_field_type(SIMPLE);
        response.set_message("OK".as_bytes().to_vec());
        Ok(response)
    }

    fn attr(&self) -> CmdAttr {
        SET_CMD_ATTR
    }
}

const GET_CMD_ATTR: CmdAttr = CmdAttr::new("GET", 2);
const SET_CMD_ATTR: CmdAttr = CmdAttr::new("SET", -3);